#include <stdlib.h>
#include <math.h>
#define PI 3.14159265359



float* MatrixMultiplication4x4(float* m1, float* m2)
{
	float *m3;

	m3 = (float*)malloc(16*sizeof(float));

	m3[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
	m3[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
	m3[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
	m3[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
	m3[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
	m3[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
	m3[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
	m3[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
	m3[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
	m3[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
	m3[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
	m3[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
	m3[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
	m3[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
	m3[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
	m3[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];

	return m3;
}

float* MatrixScale(float x, float y, float z)
{
	float *Mscale;

	Mscale = (float*)malloc(16*sizeof(float));
	
	Mscale[ 0] = x;
	Mscale[ 1] = 0;
	Mscale[ 2] = 0;
	Mscale[ 3] = 0;
	Mscale[ 4] = 0;
	Mscale[ 5] = y;
	Mscale[ 6] = 0;
	Mscale[ 7] = 0;
	Mscale[ 8] = 0;
	Mscale[ 9] = 0;
	Mscale[10] = z;
	Mscale[11] = 0;
	Mscale[12] = 0;
	Mscale[13] = 0;
	Mscale[14] = 0;
	Mscale[15] = 1;

	return Mscale;
}

float* MatrixTranslation(float x, float y, float z)
{
	float* Mtranslation;

	Mtranslation = (float*)malloc(16*sizeof(float));
	
	Mtranslation[ 0] = 1;
	Mtranslation[ 1] = 0;
	Mtranslation[ 2] = 0;
	Mtranslation[ 3] = 0;
	Mtranslation[ 4] = 0;
	Mtranslation[ 5] = 1;
	Mtranslation[ 6] = 0;
	Mtranslation[ 7] = 0;
	Mtranslation[ 8] = 0;
	Mtranslation[ 9] = 0;
	Mtranslation[10] = 1;
	Mtranslation[11] = 0;
	Mtranslation[12] = x;
	Mtranslation[13] = y;
	Mtranslation[14] = z;
	Mtranslation[15] = 1;
	
	return Mtranslation;
}


/////////////////////////////////////////////
//	Matriz de Rotação X
//
//	|  1      0      0      0  |
//	|  0    cos()  sen()    0  |
//	|  0   -sen()  cos()    0  |
//	|  0      0      0      1  |
/////////////////////////////////////////////

float* MatrixRotationX(float rotation)
{
	float *Mrotation;

	rotation = rotation*PI/180; // Conversão de graus para rad.

	Mrotation = (float*)malloc(16*sizeof(float));

	Mrotation[0] = 1.0f;
	Mrotation[1] = 0.0f;
	Mrotation[2] = 0.0f;
	Mrotation[3] = 0.0f;
	Mrotation[4] = 0.0f;
	Mrotation[5] = (float)cos(rotation);
	Mrotation[6] = (float)sin(rotation);
	Mrotation[7] = 0.0f;
	Mrotation[8] = 0.0f;
	Mrotation[9] = (float)(-sin(rotation));
	Mrotation[10] = (float)cos(rotation);
	Mrotation[11] = 0.0f;
	Mrotation[12] = 0.0f;
	Mrotation[13] = 0.0f;
	Mrotation[14] = 0.0f;
	Mrotation[15] = 1.0f;

	return Mrotation;
}



/////////////////////////////////////////////
//	Matriz de Rotação Y
//
//	|  cos()    0     sen()   0   |
//	|    0      1      0      0   |
//	| -sen()    0     cos()   0   |
//	|    0      0      0      1   |
/////////////////////////////////////////////
float* MatrixRotationY(float rotation)
{
	float *Mrotation;

	rotation = rotation*PI/180; // Conversão de graus para rad.

	Mrotation = (float*)malloc(16*sizeof(float));

	Mrotation[0] = (float)cos(rotation);
	Mrotation[1] = 0.0f;
	Mrotation[2] = (float)(-sin(rotation));
	Mrotation[3] = 0.0f;
	Mrotation[4] = 0.0f;
	Mrotation[5] = 1.0f;
	Mrotation[6] = 0.0f;
	Mrotation[7] = 0.0f;
	Mrotation[8] = (float)sin(rotation);
	Mrotation[9] = 0.0f;
	Mrotation[10] = (float)cos(rotation);
	Mrotation[11] = 0.0f;
	Mrotation[12] = 0.0f;
	Mrotation[13] = 0.0f;
	Mrotation[14] = 0.0f;
	Mrotation[15] = 1.0f;

	return Mrotation;
}



//////////////////////////////////////////
//	Matriz de Rotação Z
//
//	|  cos() -sen()    0      0  |
//	|  sen()  cos()    0      0  |
//	|    0      0      1      0  |
//	|    0      0      0      1  |
//////////////////////////////////////////
float* MatrixRotationZ(float rotation)
{
	float *Mrotation;

	rotation = rotation*PI/180; // Conversão de graus para rad.

	Mrotation = (float*)malloc(16*sizeof(float));

	Mrotation[0] = (float)cos(rotation);
	Mrotation[1] = (float)sin(rotation);
	Mrotation[2] = 0.0f;
	Mrotation[3] = 0.0f;
	Mrotation[4] = (float)(-sin(rotation));
	Mrotation[5] = (float)cos(rotation);
	Mrotation[6] = 0.0f;
	Mrotation[7] = 0.0f;
	Mrotation[8] = 0.0f;
	Mrotation[9] = 0.0f;
	Mrotation[10] = 1.0f;
	Mrotation[11] = 0.0f;
	Mrotation[12] = 0.0f;
	Mrotation[13] = 0.0f;
	Mrotation[14] = 0.0f;
	Mrotation[15] = 1.0f;

	return Mrotation;
}



////////////////////////////////////
//	Matrix de Projeção
//
//	|  Sx  0   0   0  |
//	|  0   Sy  0   0  |
//	|  0   0   Sz  Pz |
//	|  0   0   -1  0  |
////////////////////////////////////
float* MatrixProjection(float near, float far, float fov, float aspect)
{
	float range = tan (fov * 0.5f) * near;
	float Sx = (2.0f * near) / (range * aspect + range * aspect);
	float Sy = near / range;
	float Sz = -(far + near) / (far - near);
	float Pz = -(2.0f * far * near) / (far - near);

	float *Mprojection;

	Mprojection = (float*)malloc(16*sizeof(float));

	Mprojection[0] = Sx;
	Mprojection[1] = 0.0f;
	Mprojection[2] = 0.0f;
	Mprojection[3] = 0.0f;
	Mprojection[4] = 0.0f;
	Mprojection[5] = Sy;
	Mprojection[6] = 0.0f;
	Mprojection[7] = 0.0f;
	Mprojection[8] = 0.0f;
	Mprojection[9] = 0.0f;
	Mprojection[10] = Sz;
	Mprojection[11] = -1.0f;
	Mprojection[12] = 0.0f;
	Mprojection[13] = 0.0f;
	Mprojection[14] = Pz;
	Mprojection[15] = 0.0f;

	return Mprojection;
}